Skip to main content

Scooping and Flashlight-Design Documentation

1.Executive Summary

We implement an interactive, non-destructive 3D “Scooping/Flashlight” tool for vtk.js volume rendering. A fixed-size box moves through a CT volume and makes all voxels inside the box transparent by setting their scalar value to 0. This hides interior regions without permanently modifying data. Current state: translation via a center handle; no rotation handle yet (planned).

2. Scope & Goals

Scooping Viewer: IJK-aligned box built with vtkPlanes; on interaction, restore cached scalars, zero inside-box scalars, re-render.

Flashlight: oriented world-space box (wireframe cue via vtkCubeSource); masking via projection onto the box basis; non-destructive.

Always start from original (cached) scalar data per interaction.

Opacity TF maps 0 → 0 opacity so inside becomes invisible.

3.Architecture Overview

Data Flow (conceptual): UI/Widget → ScoopingWidget → (restore cached scalars) → mask inside box → vtkImageData(scalars) → vtkVolumeMapper → vtkVolume (render).
vtkCubeSource (wireframe cue) is visual only; it does not crop or mask.

Scooping Viewer — Simple Architecture Flow

alt_text

4.Data Model & Definitions

Cached Scalars: untouched copy of original voxel intensities (vtkImageData point-data).

Scalar Value: per-voxel intensity consumed by the volume mapper; opacity TF maps intensity to transparency (0 → 0 opacity).

Oriented Box (Flashlight): center C (world), size [sx, sy, sz] (world units), axes [ax, ay, az] (orthonormal).

IJK Box (Scooping): vtkPlanes define axis-aligned bounds in IJK index space.

5.Masking Algorithm (Core)

On each interaction: restore → bound → iterate → project → test → zero → render.

  1. Restore the scalar array from the cached copy (start from unmodified data).
  2. Compute an IJK bounding range from the 8 world‑space corners of the active box.
  3. For each voxel (i, j, k) in that IJK range:
  4. Convert (i, j, k) → world position p.
  5. q = p − C (vector from box center).
  6. Project: lx = dot(q, ax), ly = dot(q, ay), lz = dot(q, az).
  7. With half‑sizes hx=sx/2, hy=sy/2, hz=sz/2: if |lx|≤hx && |ly|≤hy && |lz|≤hz → INSIDE → set scalar=0.
  8. Request render; opacity TF maps 0 → 0 opacity so inside voxels become invisible.

Pseudocode — Oriented-Box Masking alt_text

Flashlight Implementation — Oriented Box Flow alt_text

6.Interaction & UX

Handles: Center handle (translation). Rotation handle: not in V1 (planned).

Highlighting: center handle hover/active; (future) rotation line turns green on pick.

7. Interaction & UX

• Handles: Center handle (translation). Rotation line/axis: NOT implemented in Version1 (planned).
• Highlighting: center handle hover/active; (future) rotation line turns green when picked.

8. Scooping Viewer vs Flashlight — Practical Notes

• Scooping Viewer uses vtkPlanes (IJK‑aligned) to define the box; masking is still done by zeroing inside‑box scalars.
• Flashlight emphasizes an oriented world‑space box; vtkCubeSource is only a wireframe cue. The masking math is identical (basis projection).
• Both approaches are non‑destructive thanks to the cached scalar restore.

9.Roadmap

  1. Version1 — Translation + masking via scalar=0; IJK‑aligned vtkPlanes; oriented‑box masking core in place.
  2. Version2 — Add rotation line/axis handle; camera‑axis unlock during rotation; highlight line (green) on pick.